#函数
#具体的某段功能代码

#关键字
#python函数定义  def
#def 函数名(参数):
#    函数体

#使用函数
#减少代码冗余，重复使用
#方便维护
#模块设计

# def add(a,b):
#     print("a+b=",a+b)
#
# add(1,2)
# add(3,4)
# add(4,5)


#形参
#实参

#按照定义来分（形参）
#必选(位置)参数 默认参数 可变长位置参数 可变长关键字参数
#注意使用顺序

#定义时，默认参数放在必选参数的后面
# def userinfo(name,age,sex="f"):
#     print(f"username is {name}, age is {age},sex is {sex}")

#位置参数调用
# userinfo("wen",18,"m")
# userinfo(18,"wen")
#关键字参数调用(不关注参数传递的顺序)
# userinfo(age=18,name="wen")
# userinfo("wen",age=18)
#调用时，位置参数要放在关键字参数的前面
#userinfo(name="wen",18)

#可变长参数的传递
#nums packing  - 打包成元组
# def myargs(*nums):
#     print(type(nums),nums)
#
# myargs(1)
# myargs(1,2)
# myargs(1,2,3)

#可变长关键字参数
#kwargs -- 打包成字典
# def mykeyargs(**kwargs):
#     print(type(kwargs),kwargs)
#
# mykeyargs(a="1",b="2",c="3")

#unpacking
#字典  --》 **  key1=value1, key2=value2
#元组  --》 *   value1,value2
# dict1 = {"a":1,"b":2}
# print(**dict1)
# print(a=1,b=2)
# print("a is {a},b is {b}".format(**dict1))
# tuple1 = (1,2)
# print(*tuple1)
#print(1,2)
# print("tuple a is {0}, b is {1}".format(*tuple1))

#python packing 和unpacking

##return语句
#没有return  默认返回None， return后面不接值返回，默认也是返回None
#按照函数处理逻辑，遇到的第一个return 就返回，函数不往下执行
# def add(a,b):
#     print(f'a和b的值为：{a+b}')
#     return 5
#     print("ending.....")
#     return 6
#
# c = add(1,3)
# d = print(c)

# import random
#匿名函数
# def add(x,y):
#     return x+y
# add(1,2)

#函数体只有一个表达式
# testlambda = lambda x,y: x+y
# print(testlambda(1,2))

# a = [-10,1,-3,0,4,6]
# #key指定的函数运算之后
# #    10，1，3，0，4，6
# # a.sort()
# # print(a)
# #key指定排序规则
# def keyfunc(x):
#     return x if x>0 else -x
#
# print(sorted(a, key= lambda x: x if x>0 else -x))
# print(sorted(a, key=keyfunc))

#递归函数
#把大问题划分成小问题
#规定出口
#函数自己调用自己
# n! = 1*2*3*4*5...*n
# 6! = 6 * 5!
# f(n) = n * f(n-1)

# def jiecheng(n):
#     #定义出口
#     if n == 1:
#         return 1
#     return n*jiecheng(n-1)
#
# print(jiecheng(4))

#斐波拉契数列
#f(n) = f(n-1)+f(n-2)
#1,1,2,3,5,8,13
# def fib(n):
#     if n == 1 or n ==2 :
#         return 1
#     return fib(n-1) + fib(n-2)
#
# lst1 = []
# for i in range(10):
#     lst1.append(fib(i+1))
# print(lst1)

#台阶问题
#每次只能走一步或者两步，求问走上n阶台阶共有多少种方法？
#到达50阶台阶的方式有两种，一种从49台阶走上来，一种从48台阶走上来
#所以： f(50) = f(48)+f(49)
# def taijie(n):
#     if n == 1 or n ==2:
#         return n
#     return taijie(n-1)+taijie(n-2)

##函数的参数传递
#本质上传递引用
#不可变数据类型
# x=10
# def f():
#     # x = 100
#     print(id(x))
#     print(x)
#
# print(x)
# # x = 1
# # print(id(x))
# f()
# print(x)

#可变数据类型
# lst1 = [1,2,3]
# def f(x):
#     x[0] = 100
#     print(x)
# f(lst1)
# print(lst1)

#参数定义时，尽量避免定义成可变数据类型
# def f(a=[]):
#     a.append(1)
#     print(a)
#
# f()
# f()
# f()


#变量的作用域
#局部变量
#全局变量
#内建变量

# def f():
#     x = 100  #局部变量
#     global a  #在局部函数里面定义全局变量
#     a = 10
#     print(x)
# # a = 5
# x=10  #全局变量
# print(__name__) #内建变量  python自带的  变量命名以双下划线开头和双下划线结尾，在python中有特殊意义
# f()
# print(a)

#变量名的解析原则：LEGB原则
#L local -- 本地函数内部
#E   在任意上一层函数的作用域查找
#G   全局变量作用域
#B    内置作用域
x = 5
def f():
    """

    
    :return:
    """
    #x = 3
    #__name__ = 4
    def f2():
        #x = 3
        print(x)
        print(__name__)
    f2()
f()